/////////////////////////////////////////////     File     //////////////////////////////////////////////////
// Author: James Chen
// Filename: CUtilities.cpp
// Created: Friday, January 29, 2010 12:13:05 PM
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include ".\CUtilities.h"

//#define	CRITICAL_SECTION_RND		// Not strictly necessary, so off for speed

////////////////////// Singleton Implementation Begins //////////////////////
RNGen *RNGen::m_pInstance = 0;

RNGen::RNGen(void)
{
	srand((unsigned)time(NULL));

	this->SEED = rand();

	MZ = rand();
	MW = rand();

	RN = 0;
}

RNGen::~RNGen(void)
{
}

RNGen *RNGen::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new RNGen;
	}

	return m_pInstance;
}

void RNGen::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}
/////////////////////// Singleton Implementation Ends ///////////////////////

void RNGen::Reseed()
{
	this->SEED = rand();
}

unsigned int RNGen::FastMW(void)
{
#ifdef		CRITICAL_SECTION_RND
	EnterCriticalSection(&rnd_CS);
#endif

	static int rnd_a = 12345678;
	static int rnd_b = 12393455;
	static int rnd_c = 45432838;

	rnd_a = rnd_a ^ 0x10010100;
	rnd_a = (rnd_a << 1) | ((rnd_a>> 31)&1);
	rnd_a ^= rnd_b ^ rnd_c;
	rnd_b = rnd_b * 255 + 32769;
	rnd_c = rnd_a + rnd_b + rnd_c + 1;

	this->RN = rnd_a;

#ifdef		CRITICAL_SECTION_RND
	LeaveCriticalSection(&rnd_CS);
#endif

	return RN;
}

unsigned int RNGen::FastW(void)
{
#ifdef		CRITICAL_SECTION_RND
	EnterCriticalSection(&rnd_CS);
#endif

	static int m_w = 12393455;    /* must not be zero */
	static int m_z = 45432838;    /* must not be zero */

    m_z = 36969 * (m_z & 65535) + (m_z >> 16);
    m_w = 18000 * (m_w & 65535) + (m_w >> 16);

	this->RN = (m_z << 16) + m_w;

#ifdef		CRITICAL_SECTION_RND
	LeaveCriticalSection(&rnd_CS);
#endif

    return RN;  /* 32-bit result */
}

unsigned int RNGen::FastI(void)
{
	RN = (214013*RN+2531011);
	RN = (RN>>16)&0x7FFF;

    return RN;  /* 32-bit result */
}

unsigned int RNGen::FastSeed(void)
{
	this->MZ = 36969 * (this->MZ & 65535) + (this->MZ >> 16);
    this->MW = 18000 * (this->MW & 65535) + (this->MW >> 16);

	this->RN = (this->MZ << 16) + this->MW;

	return RN;
}

unsigned int RNGen::Slow(void)
{
	RN = rand();
		
	return RN;
}

double RNGen::RandD(RNDTYPE TYPE, double LowValue, double HighValue)
{
	switch(TYPE)
	{
		case FASTMW:
			{
				this->Ratio = static_cast<double>(this->FastMW())/static_cast<double>(RANDMAX_FASTMW);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case FASTW:
			{
				this->Ratio = static_cast<double>(this->FastW())/static_cast<double>(RANDMAX_FASTW);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case FASTI:
			{
				this->Ratio = static_cast<double>(this->FastI())/static_cast<double>(RANDMAX_FASTI);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case FASTSEED:
			{
				this->Ratio = static_cast<double>(this->FastSeed())/static_cast<double>(RANDMAX_FASTSEED);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		case SLOW:
			{
				this->Ratio = static_cast<double>(this->Slow())/static_cast<double>(RANDMAX_SLOW);

				this->ReturnValue = ((HighValue - LowValue)*Ratio)+LowValue;

				return this->ReturnValue;
			}

		default:
			{
				return 0.0;
			}
	}
}

float RNGen::RandF(RNDTYPE TYPE, float LowValue, float HighValue)
{
	switch(TYPE)
	{
		case FASTMW:
			{
				this->Ratio = static_cast<double>(this->FastMW())/static_cast<double>(RANDMAX_FASTMW);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case FASTW:
			{
				this->Ratio = static_cast<double>(this->FastW())/static_cast<double>(RANDMAX_FASTW);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case FASTI:
			{
				this->Ratio = static_cast<double>(this->FastI())/static_cast<double>(RANDMAX_FASTI);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case FASTSEED:
			{
				this->Ratio = static_cast<double>(this->FastSeed())/static_cast<double>(RANDMAX_FASTSEED);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		case SLOW:
			{
				this->Ratio = static_cast<double>(this->Slow())/static_cast<double>(RANDMAX_SLOW);

				this->ReturnValueF = static_cast<float>(((HighValue - LowValue)*Ratio)+LowValue);

				return this->ReturnValueF;
			}

		default:
			{
				return 0.0f;
			}
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////

CTimer::CTimer(void)
{
	/* Seed the random number generator */
	srand(unsigned int(time(NULL)));

	m_nFPS = 0;
    m_dTimeStart = 0.0f;
    m_dTimeDelta = 0.0f;
}

CTimer::~CTimer(void)
{
}

void CTimer::Initialize()
{
	LARGE_INTEGER liTicks;

    /* Get processor frequency */
    QueryPerformanceFrequency(&m_liTickFrequency);

    /* Get current tick count */
    QueryPerformanceCounter(&liTicks);

    /* Set the start time */
    m_dTimeStart = float(liTicks.QuadPart) / float(m_liTickFrequency.QuadPart);

    /* Reset the frames per second */
    m_nFPS = 0;

	/* Reseed the random number generator */
	srand(unsigned int(time(NULL)));
}

void CTimer::Update(void)
{
    static double sfTimePrev = GetTimeSinceStart();
    static double sfTimeLastFrame = GetTimeSinceStart();
    static int snFrames = 0;
    double fTimeNow = GetTimeSinceStart();

    /* Increment the frame counter */
    snFrames++;

    /* Keep track of the frames per second */
    if((fTimeNow - sfTimePrev) > 1.00)
    {
        m_nFPS = snFrames / int(fTimeNow - sfTimePrev);
        snFrames = 0;
        sfTimePrev = fTimeNow;
    }

    /* Calculate the change in time */
    m_dTimeDelta = (fTimeNow - sfTimeLastFrame);
    sfTimeLastFrame = fTimeNow;
}

double CTimer::GetTimeSinceStart(void)
{
    LARGE_INTEGER liTicks;
    double fTime;

    /* Get the current tick count */
    QueryPerformanceCounter(&liTicks);

    /* get the current time since the beginning of the computer age */
    fTime = double(liTicks.QuadPart) / double(m_liTickFrequency.QuadPart);

    /* Calculate the time since the last reset */
    return (fTime - m_dTimeStart);
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////


CMath *CMath::m_pInstance = 0;

CMath::CMath(void)
{
}

CMath::~CMath(void)
{
}

CMath *CMath::GetInstance(void)
{
	if(!m_pInstance)
	{
		m_pInstance = new CMath;
	}

	return m_pInstance;
}

void CMath::DeleteInstance(void)
{
	if(m_pInstance)
	{
		delete m_pInstance;
		m_pInstance = 0;
	}
}
/////////////////////// Singleton Implementation Ends ///////////////////////

float CMath::LinearInterpolationF(const float &Min, const float &Max, const float &Progression)
{
	return ((Max-Min)*Progression)+Min;
}
double CMath::LinearInterpolationD(const double &Min, const double &Max, const double &Progression)
{
	return ((Max-Min)*Progression)+Min;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////